package com.tianhua.amis4j.service.admin;

import com.coderman.model.meta.bean.PlantUMLApiContextBean;
import com.coderman.model.meta.bean.back.*;
import com.coderman.model.meta.bean.support.PageBean;
import com.coderman.model.meta.engine.WebCodeGenerator;
import com.tianhua.amis4j.infrast.dataobject.ProjectConfigDO;
import com.tianhua.amis4j.infrast.mapper.ProjectConfigMapper;
import com.tianhua.amis4j.service.ability.ReadApiPlantUMLDocService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Description:
 * date: 2022/4/19
 *
 * @author fanchunshuai
 * @version 1.0.0
 * @since JDK 1.8
 */
@Service
public class ProjectConfigService {
    private Logger logger = LoggerFactory.getLogger(Logger.class);


    @Resource
    private ProjectConfigMapper projectConfigMapper;

    @Autowired
    private ReadApiPlantUMLDocService readApiPlantUMLDocService;

    @Autowired
    private ModuleConfigService moduleConfigService;

    @Autowired
    private ApiConfigService apiConfigService;

    @Autowired
    private ApiParamService apiParamService;

    @Autowired
    private WebCodeService webDslConfigService;


    @Autowired
    private WebCodeGenerator dslGenerator;



    public long saveProjectConfig(ProjectBean projectBean){
        ProjectConfigDO projectConfigDO = new ProjectConfigDO();
        BeanUtils.copyProperties(projectBean,projectConfigDO);
        projectConfigMapper.insert(projectConfigDO);
        return projectConfigDO.getId();
    }


    /**
     * 根据上传的文档初始化文档模型 api模型和参数模型等
     * @param projectBean
     * @param plantUMLDocPath
     */
    @Transactional(rollbackFor = Exception.class)
    public void initProjectMetaData(ProjectBean projectBean, String plantUMLDocPath){
        if(StringUtils.isEmpty(plantUMLDocPath)){
            logger.warn("plantUMLDocPath is null.........");
            return;
        }
        PlantUMLApiContextBean plantUMLApiContextBean = readApiPlantUMLDocService.readDoc(plantUMLDocPath);
        plantUMLApiContextBean.setProjectCode(projectBean.getProjectCode());
        plantUMLApiContextBean.setWebArchName(projectBean.getDslAppName());

        List<ApiBean>  apiBeanList = plantUMLApiContextBean.getApiBeanList();
        if(apiBeanList == null || apiBeanList.isEmpty()){
            return;
        }

        Set<String> moduleCodeSet = new HashSet<>();
        apiBeanList.stream().forEach(apiBean -> {
            if(!moduleCodeSet.contains(apiBean.getModuleCode())){
                ModuleBean moduleBean = ModuleBean.getInstance(projectBean.getProjectCode(), apiBean.getModuleCode(), apiBean.getModuleName());
                moduleConfigService.saveModuleConfig(moduleBean);
                moduleCodeSet.add(apiBean.getModuleCode());
            }

        });

        apiBeanList.stream().forEach(apiBean -> {
            apiBean.init(projectBean.getProjectCode());
            apiConfigService.saveApiConfig(apiBean);
        });
        
        if(CollectionUtils.isNotEmpty(plantUMLApiContextBean.getParamClassBeanList())){
            plantUMLApiContextBean.getParamClassBeanList().forEach(paramBean -> {
                paramBean.init(projectBean.getProjectCode());
                apiParamService.saveApiParam(paramBean);
            });
        }

        //是否立即进行代码生成，走默认内置的容器模式，增删改查
        if(projectBean.isCreateCode()){
            //创建web代码
            dslGenerator.createWebCode(plantUMLApiContextBean);
        }

    }


    public void updateProjectConfig(ProjectBean projectBean){
        ProjectConfigDO projectConfigDO = new ProjectConfigDO();
        BeanUtils.copyProperties(projectBean,projectConfigDO);
        projectConfigMapper.update(projectConfigDO);
    }


    public PageBean selectPage(PageBean pageBean){
        List<ProjectConfigDO> projectConfigDOList = projectConfigMapper.getPageList(pageBean);
        List<ProjectBean> projectBeanList = new ArrayList<>();
        for (ProjectConfigDO projectConfigDO : projectConfigDOList){
            ProjectBean projectBean = new ProjectBean();
            BeanUtils.copyProperties(projectConfigDO,projectBean);
            projectBeanList.add(projectBean);
        }
        pageBean.setCount(projectConfigMapper.getPageCount(pageBean));
        pageBean.setRows(projectBeanList);
        return pageBean;
    }

    /**
     * 构建聚合快照
     * @param projectCode
     * @return
     */
    public ProjectSnapShotBean buildProjectSnapShotBean(String projectCode){
        ProjectSnapShotBean projectSnapShotBean = new ProjectSnapShotBean();
        projectSnapShotBean.setProjectCode(projectCode);
        ProjectConfigDO projectConfigDO = projectConfigMapper.getByProjectCode(projectCode);
        if(projectConfigDO == null){
            logger.error("根据项目编码查不到项目信息.......");
            return null;
        }

        ProjectBean projectBean = new ProjectBean();
        BeanUtils.copyProperties(projectConfigDO,projectBean);
        projectSnapShotBean.setProjectBean(projectBean);

        List<ModuleBean> moduleBeanList = moduleConfigService.getByProjectCode(projectCode);
        projectSnapShotBean.setModuleBeanMap(moduleBeanList.stream().collect(Collectors.toMap(ModuleBean::getModuleCode,o->o)));


        Map<String,List<ApiBean>> apiBeanListMap = new HashMap<>();
        moduleBeanList.stream().forEach(moduleBean -> {
            List<ApiBean> apiBeanList = apiConfigService.getByModuleCode(moduleBean.getModuleCode());
            apiBeanListMap.put(moduleBean.getModuleCode(), apiBeanList);
        });
        projectSnapShotBean.setApiBeanListMap(apiBeanListMap);

        List<ParamBean> paramBeanList = apiParamService.selectByProjectCode(projectCode);
        Map<String,ParamBean> paramBeanMap = paramBeanList.stream().collect(Collectors.toMap(ParamBean::getParamClassName,o->o));
        projectSnapShotBean.setParamBeanMap(paramBeanMap);
        List<WebCodeBean> webDslConfigBeanList = webDslConfigService.selectByProjectCode(projectCode);
        projectSnapShotBean.setWebDslConfigBeanList(webDslConfigBeanList);

        return projectSnapShotBean;
    }

    public ProjectBean getByProjectCode(String projectCode){
        ProjectConfigDO projectConfigDO = projectConfigMapper.getByProjectCode(projectCode);
        if(projectConfigDO == null){
            return null;
        }
        ProjectBean projectBean = new ProjectBean();
        BeanUtils.copyProperties(projectConfigDO,projectBean);
        return projectBean;
    }

    /**
     * 支持名称和编码搜索
     * @param content
     * @return
     */
    public List<ProjectBean> search(String content){
        List<ProjectConfigDO> projectConfigDOList = projectConfigMapper.getAll(content);
        List<ProjectBean> projectBeanList = new ArrayList<>();
        for (ProjectConfigDO projectConfigDO : projectConfigDOList){
            ProjectBean projectBean = new ProjectBean();
            BeanUtils.copyProperties(projectConfigDO,projectBean);
            projectBeanList.add(projectBean);
        }
        return projectBeanList;
    }


    /**
     * 根据上传的Api文档增量更新modul,api,params信息
     * @param projectCode
     * @param filePath
     */
    @Transactional(rollbackFor = Exception.class)
    public void refreshApiDoc(String projectCode,String filePath){
        logger.info("刷新API文档开始,projectCode = {},filePath={}",projectCode,filePath);
        if(StringUtils.isEmpty(filePath)){
            logger.warn("plantUMLDocPath is null.........");
            return;
        }
        PlantUMLApiContextBean plantUMLApiContextBean = readApiPlantUMLDocService.readDoc(filePath);

        ProjectSnapShotBean projectSnapShotBean = buildProjectSnapShotBean(projectCode);
        List<ApiBean>  apiBeanList = plantUMLApiContextBean.getApiBeanList();
        if(apiBeanList == null || apiBeanList.isEmpty()){
            return;
        }

        Set<String> moduleCodeSet = new HashSet<>();
        apiBeanList.stream().forEach(apiBean -> {
            if(!moduleCodeSet.contains(apiBean.getModuleCode())){
                ModuleBean moduleBean = ModuleBean.getInstance(projectCode, apiBean.getModuleCode(), apiBean.getModuleName());
                if(!projectSnapShotBean.getModuleBeanMap().containsKey(apiBean.getModuleCode())){
                    moduleConfigService.saveModuleConfig(moduleBean);
                }
                moduleCodeSet.add(apiBean.getModuleCode());
            }
        });


        apiBeanList.stream().forEach(apiBean -> {
            apiBean.init(projectCode);
            List<ApiBean> oldApiBeanList = projectSnapShotBean.getApiBeanListMap().get(apiBean.getModuleCode());
            if(CollectionUtils.isEmpty(oldApiBeanList)){
                apiConfigService.saveApiConfig(apiBean);
            }else {
                Optional<ApiBean> apiBeanOptional = oldApiBeanList.stream().filter(old -> old.getMethodType().equals(apiBean.getMethodType()) && old.getApiUrl().equals(apiBean.getApiUrl())).findFirst();
                if(!apiBeanOptional.isPresent()){
                    apiConfigService.saveApiConfig(apiBean);
                }
            }
        });


        if(CollectionUtils.isNotEmpty(plantUMLApiContextBean.getParamClassBeanList())){
            plantUMLApiContextBean.getParamClassBeanList().forEach(paramBean -> {
                paramBean.init(projectCode);
                if(paramBean.isModelParam()){
                    ParamBean old = projectSnapShotBean.getParamBeanMap().get(paramBean.getParamClassName());
                    if(old == null){
                        apiParamService.saveApiParam(paramBean);
                    }
                }
            });
        }
        logger.info("刷新API文档完成..");

    }


}
